package com.common.base.http.impl.interceptor

import android.util.ArrayMap
import com.common.base.common.OfflineModule
import com.common.base.iprovider.IProviderUserOffline
import com.common.base.manager.ConfigManager
import com.common.base.tools.utils.JsonUtils
import com.common.base.tools.utils.logger
import com.didi.drouter.api.DRouter
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Protocol
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import okio.Buffer
import retrofit2.Invocation
import java.net.ConnectException

/**
 * 三疯
 * *************************
 * 离线拦截器
 * *************************
 */
class LocalOfflineInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        try {
            chain.proceed(request)
        } catch (e: ConnectException) {
            //1、允许走离线
            //2、接口支持离线
            if (ConfigManager.configBean?.isAllowOffline == true) {
                //网络异常，走离线
                val invocation = request.tag(Invocation::class.java)
                val mOfflineModule: OfflineModule?
                if (invocation != null) {
                    mOfflineModule =
                        invocation.method().getDeclaredAnnotation(OfflineModule::class.java)
                    val methodName = invocation.method().name
                    //因为有些业务表明上是一个网络请求，实际上是从本地获取数据。如试算 需要根据配置来决定是走远程还是本地
                    //当请求存在注解的时候，并且业务类型不为空，
                    if (mOfflineModule != null && mOfflineModule.module.isNotEmpty()) {
                        val resp = handle(request, mOfflineModule, methodName)
                        if (resp != null) {
                            return resp
                        }
                    }
                }
            }
        } catch (e: java.lang.Exception) {
            logger.error(e)
        }
        return chain.proceed(chain.request())
    }

    /**
     * 处理网络请求
     * @param request 请求的request
     * @param mOfflineModule 注解
     * @param responseData 服务器返回的数据
     */
    private fun handle(
        request: Request,
        mOfflineModule: OfflineModule,
        methodName: String,
        responseData: String? = null,
    ): Response? {
        val method = request.method
        val url = request.url
        if ("GET".equals(method, ignoreCase = true)) {
            val map = ArrayMap<String, Any>()
            val keys = url.queryParameterNames
            for (key in keys) {
                val value = url.queryParameter(key)
                map[key] = value
            }
            return requestLocalOffline(
                request,
                url.encodedPath,
                JsonUtils.toJson(map),
                mOfflineModule,
                responseData,
                methodName
            )
        } else if ("POST".equals(method, ignoreCase = true)) {
            val newRequest = request.newBuilder().build()
            val requestBody = newRequest.body
            val buffer = Buffer()
            requestBody?.writeTo(buffer)
            val bodyJson: String = buffer.readUtf8()
            return requestLocalOffline(
                newRequest,
                url.encodedPath,
                bodyJson,
                mOfflineModule,
                responseData,
                methodName
            )
        }
        return null
    }

    /**
     * 使用离线网络请求
     * @param request 请求的request
     * @param url 请求地址
     * @param argument 请求的参数
     * @param mOfflineModule 注解
     * @param responseData 远端是否成功
     */
    private fun requestLocalOffline(
        request: Request,
        url: String,
        argument: String?,
        mOfflineModule: OfflineModule,
        responseData: String? = null,
        methodName: String
    ): Response {
        val service =
            DRouter.build(IProviderUserOffline::class.java).setAlias(mOfflineModule.module)
                .getService()
        val offlineResponse = service.invoke(url, argument, methodName, responseData)
        return buildResponse(request).body(offlineResponse.toResponseBody("application/jsoncharset=utf-8".toMediaTypeOrNull()))
            .build()
    }

    private fun buildResponse(request: Request): Response.Builder {
        return Response.Builder().request(request).protocol(Protocol.HTTP_1_1).code(200)
            .message("offline")
    }
}